#pragma once
#include "engine.h"
#include "hw_limits.h"
#include <GL/glew.h>
#include <list>
#include <vector>
#include <map>
#include <stack>
#include <string>
#include <stdint.h>
using namespace std;

namespace HW
{

typedef uint32_t HW_COLLISION_TYPE;

namespace UID
{
#define MASK_GLOBAL_TYPE			0xC0000000
#define MASK_GLOBAL_PER_TYPE		0x3FFFFFFF

#define MASK_RESOURCE_OFFLINE		0x20000000
#define MASK_RESOURCE_TYPE			0x1F000000
#define MASK_RESOURCE_PER_TYPE		0x00FFFFFF

#define MASK_OBJECT_WORLD			0x3F000000
#define MASK_OBJECT_CHUNK			0x00FF0000
#define MASK_OBJECT_LOCAL			0x0000FFFF

#define MASK_COMPONENT_TYPE			0x3FC00000
#define MASK_COMPONENT_PER_TYPE		0x003FFFFF

// RZERO_... means number of zeros, appearing in the rigt hand side of each part, in the binary representation
#define RZERO_GLOBAL_TYPE			30
#define RZERO_GLOBAL_PER_TYPE		0

#define RZERO_RESOURCE_OFFLINE		29
#define RZERO_RESOURCE_TYPE			24
#define RZERO_RESOURCE_PER_TYPE		0

#define RZERO_OBJECT_WORLD			24
#define RZERO_OBJECT_CHUNK			16
#define RZERO_OBJECT_LOCAL			0

#define RZERO_COMPONENT_TYPE		22
#define RZERO_COMPONENT_PER_TYPE	0


#define TYPE_GLOBAL_RESOURCE	0x40000000
#define TYPE_GLOBAL_OBJECT		0x80000000
#define TYPE_GLOBAL_COMPONENT	0xC0000000

//As can be seen from global types, any id starting with 00 is illegal.
//So any function can return NULL as a way of showing unsuccessful work.
}

namespace ComponentManager
{
	typedef uint8_t		HW_COMPONENT_TYPE;
	typedef uint32_t	HW_COMPONENT_ID;
	typedef void*		HW_COMPONENT;
	typedef uint16_t	HW_UPDATE_ORDER_TYPE;

	typedef void (*CallbackCompInit)			(uint32_t count , void* poolLoc , void* prius , bool* result);
	typedef void (*CallbackCompDeInit)			(uint32_t count , void* poolLoc , bool* result);
	typedef void (*CallbackCompUpdate)			(uint32_t count , void* poolLoc , bool* result);
	typedef void (*CallbackCompSerialize)		(uint32_t count , void* poolLoc , void* serializeData , bool* result);
	typedef void (*CallbackCompDeSerialize)		(uint32_t count , void* poolLoc , void* serializeData , bool* result);
	typedef void (*CallbackCompGetRefData)		(uint32_t count , void* poolLoc , void* reflectionData , bool* result);
	typedef void (*CallbackCompSetRefData)		(uint32_t count , void* poolLoc , void* reflectionData , bool* result);

	struct CompRegData
	{
		CallbackCompInit			callbackCompInit;
		CallbackCompDeInit			callbackCompDeInit;
		CallbackCompUpdate			callbackCompUpdate[MAX_UPDATE_STAGES_PER_COMP];
		CallbackCompSerialize		callbackCompSerialize;
		CallbackCompDeSerialize		callbackCompDeSerialize;
		CallbackCompGetRefData		callbackCompGetRefData;
		CallbackCompSetRefData		callbackCompSetRefData;

		str							typeName;

		HW_UPDATE_ORDER_TYPE		updateOrder[MAX_UPDATE_STAGES_PER_COMP];

		uint32_t					maxInstances;

		uint32_t					dataSize;
		uint32_t					serializationSize;
		uint32_t					reflectionSize;

		HW_COMPONENT_TYPE			typeID;

		uint8_t						padding[3];
	};

	struct UpdateElement
	{
		CallbackCompUpdate updateFunc;
		uint32_t count;
		void* poolLoc;
		bool* result;
		HW_UPDATE_ORDER_TYPE order;
		uint8_t padding[2];
	};

	struct UpdateChain
	{
		UpdateElement* element;
		uint32_t count;
	};

}

namespace Resource
{
struct _i_Shader
{
	GLuint id;
	map<string,GLint> uniformMap;
	map<string,GLint> attribMap;
};

struct _i_Buffer
{
	GLuint id;
	TTexture colTex[4];
	TTexture depTex;
	GLuint width, height;
	GLsizei drawBuffsNum;
};

struct _i_Texture
{
	GLuint id;
	GLuint width, height;
};

struct _i_Surface
{
	union
	{
		struct
		{
			GLuint indexBufID;
			GLuint positionBufID;
			GLuint normalBufID;
			GLuint colorBufID;
			GLuint UVMapBufID;
			GLuint tangentBufID;
		};
		GLuint ID[6];
	};

	GLuint vertNum;
	GLuint trisNum;
};

#define MASK_MATERIAL_DEPTH_MASK	1 << 7
#define MASK_MATERIAL_COLOR_MASK	1 << 6
#define MASK_MATERIAL_DEPTH_TEST	1 << 5
#define MASK_MATERIAL_CAST_SHADOW	1 << 4
#define MASK_MATERIAL_INVISIBLE		1 << 3
#define MASK_MATERIAL_CULL_FACE		1 << 2
#define MASK_MATERIAL_OVERLAY		1 << 1

struct _i_Material
{
	TShader shader;
	TShader shadowShader;

	TTexture texture[HW_MAX_TEXTURE_SLOTS];

	uint32_t clampMask; // 16 dual bools ( clampn(x,y) where n is from 0 to 15 )
	TVec4 color;
	
	float specular;
	float gloss;
	float bumpscale;

	HW_COLLISION_TYPE collisionType;

	string name;

	uint8_t boolMask; // 0 | depthmask | colormask | depthtest | castshadows | invisible | cullface | overlay
	int8_t zsort;
	uint8_t blend;

	uint8_t padding[1];
};

struct _i_Mesh
{
	TSurface surface[HW_MAX_SUB_MESHES];
	TMaterial material[HW_MAX_SUB_MESHES];

	uint8_t surfaceCount;
};

}

namespace Renderer
{
struct Mesh
{
	TMesh mesh;
	TVec16 matrix;
};

struct Light
{
	TLight light;
	TVec16 matrix;
};
}

namespace GameObject
{

struct _i_Transform
{
	TVec3 position;
	TVec3 rotation;
	TVec3 scale;
	TVec16 mat;
	TVec6 localaabb;
	TVec6 aabb;
};

struct _i_Hierarchy
{
	TEntity parent;
	list<TEntity> kids;
};

enum _i_EntityType
{
	_I_ENTITY_TYPE_BODY = 0,
	_I_ENTITY_TYPE_CONTROLLER,
	_I_ENTITY_TYPE_MODEL,
	_I_ENTITY_TYPE_TERRAIN,
	_I_ENTITY_TYPE_BONE,
	_I_ENTITY_TYPE_CAMERA,
	_I_ENTITY_TYPE_CORONA,
	_I_ENTITY_TYPE_LIGHT,
	_I_ENTITY_TYPE_DIRLIGHT,
	_I_ENTITY_TYPE_POINTIGHT,
	_I_ENTITY_TYPE_SPOTLIGHT,
	_I_ENTITY_TYPE_LISTENER,
	_I_ENTITY_TYPE_MESH,
	_I_ENTITY_TYPE_PIVOT,

};

struct _i_FreeablePair
{
	vector<BP>* vecBase;
	vector<BP>::iterator vecIt;
};

typedef uint32_t HW_OBJECT_ID;

#define HW_LOCALID_TYPE unsigned int
#define HW_GLOBALID_TYPE unsigned int
#define HW_COMBINEDID_TYPE unsigned int

#define ID_MASK_ENTITY	0x000FFFFF
#define ID_MASK_WORLD	0xFFF00000

struct _i_Entity
{
	_i_Transform transform; //local transform
	_i_Hierarchy hierarchy;
	int collisionType;
	map<string,string> key;
	
	string name;

	BP userData;

	TVec4 color;

	int occlusionMode;
	bool isHidden;

	_i_EntityType objType;
};

struct _i_Mesh
{
	_i_Entity entity;
	vector<pair<TSurface,TMaterial> > surface;
};

struct _i_Body
{
	_i_Entity entity;
};

struct _i_Model
{
	_i_Entity entity;
	TBody body;
	vector<TMesh> mesh;
	vector<float> lodDis;
};

struct _i_Camera
{
	_i_Entity entity;
	TVec4 clearColor;
	int clearMode;
	int projMode;
	float nearRange;
	float farRange;
	float zoom;
	TVec4 clipPlane;
};

struct _i_Pivot
{
	_i_Entity entity;
};
};

struct _i_World
{
	/*HW_COMBINEDID_TYPE worldIDMask;

	stack<HW_LOCALID_TYPE> freeLocalID;
	stack<HW_GLOBALID_TYPE> freeGlobalID;

	////////////////////////////////////////////////////////////
	//All of the following vectors should be of the same size.
	//They are actually SOA of the entity struct :)
	vector<_i_Transform> trans;
	vector<_i_Hierarchy> hier;
	vector<int> collisionType;
	vector<map<string,string>> key;
	vector<stack<_i_FreeablePair>*> toBeFreed; //actually a pointer to some pre-defined freeing chain inited globally
	vector<BP> userData;
	vector<_i_EntityType> type;
	vector<BP> typeData;
	vector<HW_GLOBALID_TYPE> globalID;
	////////////////////////////////////////////////////////////*/

	//map<HW_GLOBALID_TYPE,HW_LOCALID_TYPE> localID;

	vector<GameObject::_i_Mesh> mesh;
	vector<GameObject::_i_Model> model;
	//vector<HW_LOCALID_TYPE> emitter;
	//vector<HW_LOCALID_TYPE> terrain;
	//vector<HW_LOCALID_TYPE> corona;
	vector<GameObject::_i_Body> body;
	//vector<HW_LOCALID_TYPE> listener;
	vector<GameObject::_i_Camera> camera;
	vector<GameObject::_i_Pivot> pivot;
	//vector<HW_LOCALID_TYPE> joint;
	//vector<HW_LOCALID_TYPE> controller;

	TVec3 size;
	TVec3 range;
};

}